#include <iostream>
#include <vector>
#include <signal.h>
#include <unistd.h>

// #define BLOCK_SIGNAL 2
#define MAX_SIGNO 31

static std::vector<int> sigarr = {2,3};//要修改处理行为的信号

static void show_pending(const sigset_t &pending)
{
    for(int signo = MAX_SIGNO; signo >= 1 ; signo--)//左边是高信号位，我们反过来打印，看的舒服
    {
        if(sigismember(&pending, signo))//将内核中的pending信号集内容 拿到 用户层的pending信号集来，在用户pending信号集中判定信号是否存在
            std::cout<<"1";
        else
            std::cout<<"0";
    }
    std::cout<<"\n";// 转义字符，不用std::endl，奇奇怪怪的写法
}

static void myhandler(int signo)
{
    std::cout<<signo<<"号信号，已经被递达 进行自定义处理了!!!"<<std::endl;
}
int main()
{

    //捕捉一下2，3信号，让他们的处理行为不是终止进程，并且我还想看看捕捉信号后pending位图的结果。
    
    for(auto &sig : sigarr) signal(sig, myhandler);//注册对应信号的处理行为


    // 1.屏蔽指定的信号 -- 2号信号
    sigset_t block, oblock, pending;
    // 1.1 初始化
    sigemptyset(&block);
    sigemptyset(&oblock);
    sigemptyset(&pending);
    // 1.2 添加要屏蔽的信号
    // sigaddset(&block,BLOCK_SIGNAL);
    for(auto &sig : sigarr)// 批量化的屏蔽信号 --> 9号信号不能被屏蔽，不能在递达处理时用signal()捕捉
        sigaddset(&block, sig);

//上面是OS在用户层定义的数据类型，定义出来的block,oblock等变量处于当前函数内部，未影响进程PCB

    // 1.3 开始屏蔽，将信号屏蔽字设置进内核(进程)
    sigprocmask(SIG_SETMASK, &block, &oblock);

    // 2.遍历打印pending信号集
    int cnt = 10;
    while(true)
    {
        // 2.1 初始化 --> 将用户层定义的pending信号集初始化清零
        sigemptyset(&pending);
        // 2.2 获取pending信号集 --> 覆盖式的获取，所以前面即使不初始化清零也没有关系
        sigpending(&pending);// 系统调用接口，从内核中拿pending表内容放到用户层中
        // 2.3 打印pending信号集
        show_pending(pending);

        sleep(1);
        if(cnt-- == 0)
        {
            //下面的系统调用就会陷入内核，帮助我们修改内核的block信号集，然后进行检测，发现pending信号集有2号信号，此时就会递达处理该信号
            //此时信号就进入了捕捉流程，返回用户态执行自定义行为
            sigprocmask(SIG_SETMASK,&oblock, nullptr);//如果你想要下次再恢复到屏蔽信号的状态，那我再给你保存起来
            //一旦对特定信号解除屏蔽之后，一般OS要立马给进程至少递达一个信号
            //调用sigprocmask后会陷入内核，顺便检测信号，发现收到2号信号后默认终止进程，此时不会返回用户态执行剩余代码，下面一行就打印不出来
            //只有处理行为是自定义或忽略时，才会返回用户态执行剩余代码.
            std::cout<<"解除对信号的屏蔽，不屏蔽任何信号\n";
        }
    }
    return 0;
}
// while :; do ps axj | head -1 && ps axj | grep mysignal | grep -v grep; sleep 1; done

